//
//  LabelPrinter.swift
//  imember_printer
//
//  Created by feibi on 2022/2/14.
//

import UIKit
import PrinterSDK

class LabelPrinter: NSObject {
    /// ZPL指令
    private let zpl: PTCommandZPL = PTCommandZPL()
    
    /// 标签宽度
    private let labelWidth = 1200
    /// 标签高度
    private let labelHeight = 1800
    
    private let value1Width = 330
    private let value2Width = 133
    private let value3Width = 133
    private let value4Width = 133
    
    /// 表格宽度
    private var tableWidth: Int {
        return value1Width + value2Width + value3Width + value4Width
    }
    
    // MARK: - Public_M
    public func appendImage(_ imageData: Data) {
        let image = UIImage(data: imageData)?.cgImage
        if let image = image {
            zpl.dg_DownloadGraphics(with: image, bitmapMode: .dithering, compress: .LZO, deviceLocation: .R, imageName: "labelImage", extension: "GRF")
        }
        zpl.xa_FormatStart()
        zpl.pw_PrintWidth(1200)
        zpl.ll_LabelLength(1800)
        zpl.lh_LabelHome(withXPos: 0, yPos: 0)
        zpl.xg_RecallGraphic(withSourceDevice: .R, imageName: "labelImage", extension: "GRF", xAxisMagnification: 1, yAxisMagnification: 1)
        zpl.fs_FieldSeparator()
        zpl.xz_FormatEnd()
        
        
        zpl.xa_FormatStart()
        zpl.id_ImageDelete(withObjectLocation: .R, objectName: "labelImage", extension: "GRF")
        zpl.xz_FormatEnd()
    }
    
    public func printShippingLabel(result: @escaping FlutterResult) {
        /// 下载图片
        downloadImages()
        
        zpl.xa_FormatStart()
        zpl.pw_PrintWidth(1200)
        zpl.ll_LabelLength(1800)
        zpl.ci_ChangeInternationalCharacterSet("14")
        zpl.lh_LabelHome(withXPos: 65, yPos: 0)
    
        var yAxis = 64
        
        appendText("旅行社：台灣", xAxis: 0, yAxis: yAxis, width: 30, height: 35)
        appendText("導遊：雨澤", xAxis: labelWidth / 2, yAxis: yAxis, width: 30, height: 35)
        
        yAxis = yAxis + 35 + 30
        
        appendText("顧客姓名：張三", xAxis: 0, yAxis: yAxis, width: 30, height: 35)
        appendText("電話：0923241234", xAxis: labelWidth / 2, yAxis: yAxis, width: 30, height: 35)
        
        yAxis = yAxis + 35 + 40
        
        appendText("訂單明細", xAxis: 130, yAxis: yAxis, width: 30, height: 35)
        appendText(String("第2箱 共計10箱".reversed()), xAxis: tableWidth - 64, yAxis: yAxis, width: 30, height: 35, justification: .right)
        
        yAxis = yAxis + 35 + 12
        
        /// 二维码
        appendQRCode("21435234", xAxis: tableWidth + 34, yAxis: yAxis)
        
        /// 表格网线
        let tableHeight = 58 + 12 * 69
        appendLine(xAxis: 0, yAxis: yAxis, width: 1, height: tableHeight, thickness: 1)
        appendLine(xAxis: value1Width, yAxis: yAxis, width: 1, height: tableHeight, thickness: 1)
        appendLine(xAxis: value1Width + value2Width, yAxis: yAxis, width: 1, height: tableHeight, thickness: 1)
        appendLine(xAxis: value1Width + value2Width + value3Width, yAxis: yAxis, width: 1, height: tableHeight, thickness: 1)
        appendLine(xAxis: tableWidth, yAxis: yAxis, width: 1, height: tableHeight, thickness: 1)
        
        /// 表格头部
        appendTableRow(yAxis: yAxis, value1: "品名", value2: "單價", value3: "數量", value4: "金額", blockHeight: 58, textWidth: 24, textHeight: 28, value1Black: true, value2Black: true, value3Black: true, value4Black: true)
        
        yAxis = yAxis + 58
        
        /// 表格内容
        let rowHeight = 69
        for i in 0..<12 {
            let tableRowYAxis = yAxis + rowHeight * i
            appendLine(xAxis: 0, yAxis: tableRowYAxis + rowHeight, width: tableWidth, height: 1, thickness: 1)
            if i == 12 - 1 {
                appendTableRow(yAxis: tableRowYAxis, value1: "總計", value2: nil, value3: "36", value4: "432", blockHeight: rowHeight, value1Black: true)
            } else {
                appendTableRow(yAxis: tableRowYAxis, value1: "貢糖", value2: "12", value3: "3", value4: "36", blockHeight: rowHeight)
            }
        }
        
        zpl.lh_LabelHome(withXPos: 0, yPos: 0)
        
        yAxis = yAxis + rowHeight * 12 + 30
        
        /// 注意事项图片
        appendImage(name: "precautions", xAxis: 0, yAxis: yAxis)
        
        yAxis = yAxis + 387
        
        /// logo图片
        appendImage(name: "logo", xAxis: 202, yAxis: yAxis)
        
        yAxis = yAxis + 43
        
        /// 公司信息
        let companyAxis = 202 + 190 + 30
        appendText("聖 祖 股 份 有 限 公 司", xAxis: companyAxis, yAxis: yAxis, width: 48, height: 48)
        yAxis = yAxis + 48 + 25
        appendText("金門縣金寧鄉伯玉路2段301號  電話：082-323456", xAxis: companyAxis, yAxis: yAxis, width: 25, height: 30)
        
        zpl.xz_FormatEnd()
        
        /// 删除图片
        deleteImages()
        
        sendData(result: result)
    }
    
    /// 发送数据
    public func sendData(result: @escaping FlutterResult) {
        if PTDispatcher.share().printerConnected == nil {
            ProgressHUDManager.showInfo(message: "打印機未連接，請先連接")
            result(FlutterError.customizeFailedMessage("The printer is not connected, please connect first"))
            return
        }
        
        PTDispatcher.share().send(zpl.cmdData as Data)
        
        PTDispatcher.share().whenSendSuccess { _, _ in
            ProgressHUDManager.showSuccess(message: "數據發送成功")
            result(nil)
        }
        
        PTDispatcher.share().whenSendFailure {
            ProgressHUDManager.showSuccess(message: "數據發送失敗")
            result(FlutterError.customizeFailedMessage("Failed to send data"))
        }
    }
    
    // MARK: - Private_M
    /// 文字
    ///
    /// text：文字
    /// xAxis：x轴位置
    /// yAxis：y轴位置
    /// width：文字宽度
    /// height：文字高度
    /// justification：对齐方式
    private func appendText(_ text: String, xAxis: Int, yAxis: Int, width: Int, height: Int, justification: PTZplJustification = .left) {
        zpl.a_SetFont(with: .N, height: height, width: width, location: .E)
        zpl.fo_FieldOrigin(withXAxis: xAxis, yAxis: yAxis, justification: justification)
        zpl.fd_FieldData(text)
    }
    
    /// 居中文字
    ///
    /// text：文字
    /// xAxis：x轴位置
    /// yAxis：y轴位置
    /// width：文字宽度
    /// height：文字高度
    /// blockWidth：文本域宽度
    /// blockHeight：文本域高度
    /// isBlackBackground：是否为黑色背景
    private func appendCenterText(_ text: String?, xAxis: Int, yAxis: Int, width: Int, height: Int, blockWidth: Int, blockHeight: Int, isBlackBackground: Bool = false) {
        if isBlackBackground {
            zpl.fo_FieldOrigin(withXAxis: xAxis, yAxis: yAxis)
            zpl.gb_GraphicBox(withWidth: blockWidth, height: blockHeight, thickness: min(blockWidth, blockHeight))
            zpl.fs_FieldSeparator()
        }
        
        guard let text = text else { return }
        
        zpl.a_SetFont(with: .N, height: height, width: width, location: .E)
        zpl.fo_FieldOrigin(withXAxis: xAxis, yAxis: yAxis + (blockHeight - height) / 2)
        zpl.fb_fieldBlock(width: blockWidth)
        if isBlackBackground {
            zpl.fr_FieldReversePrint()
        }
        zpl.fd_FieldData(text)
    }
    
    /// 二维码
    ///
    /// content：二维码内容
    /// xAxis：x轴位置
    /// yAxis：y轴位置
    private func appendQRCode(_ content: String, xAxis: Int, yAxis: Int) {
        zpl.fo_FieldOrigin(withXAxis: xAxis, yAxis: yAxis)
        zpl.bq_BarcodeQRcode(with: .N, model: ._2, magnification: 10, reliabilityLevel: .M)
        zpl.fd_FieldData(content)
    }
    
    /// 线条
    ///
    /// xAxis：x轴位置
    /// yAxis：y轴位置
    /// width：线条宽度
    /// height：线条高度
    /// thickness：线条粗细
    private func appendLine(xAxis: Int, yAxis: Int, width: Int, height: Int, thickness: Int) {
        zpl.fo_FieldOrigin(withXAxis: xAxis, yAxis: yAxis)
        zpl.gb_GraphicBox(withWidth: width, height: height, thickness: thickness)
        zpl.fs_FieldSeparator()
    }
    
    /// 下载图片
    private func downloadImages() {
        let logoImage = UIImage(named: "logo", in: Bundle(for: LabelPrinter.self), compatibleWith: nil)?.cgImage
        let precautionsImage = UIImage(named: "precautions", in: Bundle(for: LabelPrinter.self), compatibleWith: nil)?.cgImage
        if let logoImage = logoImage {
            zpl.dg_DownloadGraphics(with: logoImage, bitmapMode: .dithering, compress: .LZO, deviceLocation: .R, imageName: "logo", extension: "GRF")
        }
        if let precautionsImage = precautionsImage {
            zpl.dg_DownloadGraphics(with: precautionsImage, bitmapMode: .dithering, compress: .LZO, deviceLocation: .R, imageName: "precautions", extension: "GRF")
        }
    }
    
    /// 删除图片
    private func deleteImages() {
        zpl.xa_FormatStart()
        zpl.id_ImageDelete(withObjectLocation: .R, objectName: "logo", extension: "GRF")
        zpl.id_ImageDelete(withObjectLocation: .R, objectName: "precautions", extension: "GRF")
        zpl.xz_FormatEnd()
    }
    
    /// 图片
    ///
    /// name: 图片名称
    /// xAxis：x轴位置
    /// yAxis：y轴位置
    private func appendImage(name: String, xAxis: Int, yAxis: Int) {
        zpl.fo_FieldOrigin(withXAxis: xAxis, yAxis: yAxis)
        zpl.xg_RecallGraphic(withSourceDevice: .R, imageName: name, extension: "GRF", xAxisMagnification: 1, yAxisMagnification: 1)
        zpl.fs_FieldSeparator()
    }
    
    private func appendTableRow(
        yAxis: Int,
        value1: String?,
        value2: String?,
        value3: String?,
        value4: String?,
        blockHeight: Int,
        textWidth: Int = 20,
        textHeight: Int = 23,
        value1Black: Bool = false,
        value2Black: Bool = false,
        value3Black: Bool = false,
        value4Black: Bool = false
    ) {
        appendCenterText(value1, xAxis: 0, yAxis: yAxis, width: textWidth, height: textHeight, blockWidth: value1Width, blockHeight: blockHeight, isBlackBackground: value1Black)
        appendCenterText(value2, xAxis: value1Width, yAxis: yAxis, width: textWidth, height: textHeight, blockWidth: value2Width, blockHeight: blockHeight, isBlackBackground: value2Black)
        appendCenterText(value3, xAxis: value1Width + value2Width, yAxis: yAxis, width: textWidth, height: textHeight, blockWidth: value3Width, blockHeight: blockHeight, isBlackBackground: value3Black)
        appendCenterText(value4, xAxis: value1Width + value2Width + value3Width, yAxis: yAxis, width: textWidth, height: textHeight, blockWidth: value4Width, blockHeight: blockHeight, isBlackBackground: value4Black)
    }
}

extension PTCommandZPL {
    func fb_fieldBlock(width: Int) {
        let command = "^FB" + String(width) + ",,,C"
        let commandData = command.data(using: .utf8)!
        cmdData.append(commandData)
    }
}
